﻿using System;
using System.Collections.Generic;
using System.Text;
using AIRO.Devices.Solenoid;
using MDR32Lib;
using Ivi.Driver.Interop;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Text.RegularExpressions;
using Ivi.ConfigServer.Interop;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
//using System.ComponentModel;

namespace AIRO.Devices.PositioningDevice
{
    [Guid("1E170191-D4D2-4f5f-97EA-1F8F0F20F8C9")]
    [ClassInterface(ClassInterfaceType.None)]
    [ProgId("MyDevices.PositioningDevice.MDR32Device")]
    public class MDR32Device : BasicIviDriver, Ivi.Driver.Interop.IIviDriver, IIviDriverIdentity, IIviComponentIdentity, IIviDriverOperation, IIviDriverUtility, ISolenoid, IPositioningDevice
    {
        private MDR32Lib.MdrClass mdrObj = new MDR32Lib.MdrClass();
        private MDR32Lib.MdrChan mdrCh;
        private int currState;
        private string channelName = "Solenoid";
        private double rate;
        private double maxPos;
        private double minPos;
        private SynchronizationContext context;

        public MDR32Device()
            : base()
        {
            Debug.WriteLine("Hi! I'm initializing");
            _description = "IVI Custom MDR32 Solenoid Driver";
            _identifier = "MDR32Solenoid";
            _instrumentManufacturer = "Volkov";
            _supportedInstrumentModels = "MDR32";
            _vendor = "LNEP ISSP(RAS)";
            context = SynchronizationContext.Current;
        }

        #region ISolenoid Members

        public double MagnetField
        {
            get
            {
                if (_initialized)
                {
                    if (channelName == "Solenoid")
                    {
                        return mdrCh.Val;
                    }
                    else
                    {
                        throw new Exception("You can't use this property because channel name is NOT 'Solenoid'");
                    }

                }
                else
                {
                    throw (new Exception("Driver is not initialized"));
                }
            }

        }

        SolenoidState ISolenoid.State
        {
            get
            {
                if (_initialized)
                {
                    if (channelName == "Solenoid")
                    {
                        switch (mdrCh.State)
                        {
                            case (int)MDR32Lib.mdrState.mdrRunning:
                                return SolenoidState.Running;

                            case (int)mdrState.mdrIdle:
                                return SolenoidState.Idle;

                            case (int)mdrState.mdrError:
                                return SolenoidState.Error;

                            default:
                                return SolenoidState.Error;
                        }
                    }
                    else
                    {
                        throw new Exception("You can't use this property because channel name is NOT 'Solenoid'");
                    }
                }
                else
                {
                    throw (new Exception("Driver is not initialized"));
                }


            }
        }

        public string MDRErrorInfo
        {
            get
            {
                if (_initialized)
                {
                    return mdrCh.ErrorInfo;
                }
                else
                {
                    throw (new Exception("Driver is not initialized"));
                }

            }
        }

        public void BeginGotoField(double field)
        {

            if (_initialized)
            {
                if (channelName == "Solenoid")
                {
                    mdrCh.Wind(field);
                }
                else
                {
                    throw new Exception("You can't use this property because channel name is NOT 'Solenoid'");
                }
            }
            else
            {
                throw (new Exception("Driver is not initialized"));
            }


        }

        public void Cancel()
        {
            if (currState == (int)MDR32Lib.mdrState.mdrRunning)
                mdrCh.Stop();
        }

        private EventHandler<AIRO.Devices.Solenoid.StateChangedEventArgs> solenoidStateChangedEvent;
        private EventHandler<AIRO.Devices.Solenoid.FieldSetEventArgs> solenoidFieldSetEvent;
        private EventHandler<AIRO.Devices.Solenoid.ProgressEventArgs> solenoidProgressEvent;

        event EventHandler<Solenoid.StateChangedEventArgs> ISolenoid.StateChangedEvent
        {
            add
            {
                solenoidStateChangedEvent += value;
            }
            remove
            {
                solenoidStateChangedEvent -= value;
            }
        }
        event EventHandler<Solenoid.FieldSetEventArgs> ISolenoid.FieldSetEvent
        {
            add
            {
                solenoidFieldSetEvent += value;
            }
            remove
            {
                solenoidFieldSetEvent -= value;
            }
        }
        event EventHandler<Solenoid.ProgressEventArgs> ISolenoid.ProgressEvent
        {
            add
            {
                solenoidProgressEvent += value;
            }
            remove
            {
                solenoidProgressEvent -= value;
            }
        }

        protected virtual void OnStateChangedEvent(Solenoid.StateChangedEventArgs e)
        {
            context.Post(new SendOrPostCallback(delegate(object obj)
            {
                Solenoid.StateChangedEventArgs args = (Solenoid.StateChangedEventArgs)obj;
                EventHandler<Solenoid.StateChangedEventArgs> handler = solenoidStateChangedEvent;
                if (handler != null)
                {
                    handler(this, args);
                }
            }),e);
        }

        protected virtual void OnFieldSetEvent(Solenoid.FieldSetEventArgs e)
        {
            context.Post(new SendOrPostCallback(delegate(object obj)
            {
                Solenoid.FieldSetEventArgs args = (Solenoid.FieldSetEventArgs)obj;
                EventHandler<Solenoid.FieldSetEventArgs> handler = solenoidFieldSetEvent;
                if (handler != null)
                {
                    handler(this, args);
                }
            }),e);
        }

        protected virtual void OnProgressEvent(Solenoid.ProgressEventArgs e)
        {
            context.Post(new SendOrPostCallback(delegate(object obj)
            {
                Solenoid.ProgressEventArgs args = (Solenoid.ProgressEventArgs)obj;
                EventHandler<Solenoid.ProgressEventArgs> handler = solenoidProgressEvent;
                if (handler != null)
                {
                    handler(this, args);
                }
            }),e);
        }

        #endregion

        private void mdrCh_onProgress(double Pos, double Val)
        {
            if (channelName == "Solenoid")
            {
                OnProgressEvent(new Solenoid.ProgressEventArgs(Val));
            }
            OnProgressEvent(new PositioningDevice.ProgressEventArgs(Val));
            //throw new NotImplementedException();
        }

        private void mdrCh_onStateChanged(short newState)
        {
            SolenoidState solenoidState;
            PositioningDeviceState positioningDeviceState;
            switch (newState)
            {
                case (int)MDR32Lib.mdrState.mdrRunning:
                    solenoidState = SolenoidState.Running;
                    positioningDeviceState = PositioningDeviceState.Running;
                    break;
                case (int)mdrState.mdrIdle:
                    solenoidState = SolenoidState.Idle;
                    positioningDeviceState = PositioningDeviceState.Idle;
                    if (currState == (int)mdrState.mdrRunning)
                    {
                        if (channelName == "Solenoid")
                        {
                            OnFieldSetEvent(new FieldSetEventArgs(mdrCh.Val));
                        }
                        OnFinishEvent(new PositioningDevice.FinishEventArgs(mdrCh.Val));
                    }
                    break;
                case (int)mdrState.mdrError:
                    solenoidState = SolenoidState.Error;
                    positioningDeviceState = PositioningDeviceState.Error;
                    
                    break;
                default:
                    solenoidState = SolenoidState.Error;
                    positioningDeviceState = PositioningDeviceState.Error;
                    break;
            }
            if (channelName == "Solenoid")
            {                
                OnStateChangedEvent(new Solenoid.StateChangedEventArgs(solenoidState));
            }
            OnStateChangedEvent(new PositioningDevice.StateChangedEventArgs(positioningDeviceState));

            currState = newState;
            
        }

        #region IIviDriver Members

        public void Close()
        {
            if (_initialized)
            {
                mdrCh.Stop();
                _initialized = false;
                //throw new NotImplementedException();
            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
            }
        }

        public void Initialize(string ResourceName, bool IdQuery, bool Reset, string OptionString)
        {
            if (!_initialized)
            {
                _rangeCheck = true;
                _cache = true;
                _queryInstrumentStatus = false;
                _simulate = false;
                _driverSetup = "";
                _recordCoercions = false;
                _interchangeCheck = false;
                resourceName = "Not Applicable";
                _logicalName = ResourceName;
                IviDriverSession iviSession = ReadConfigStore();
                IIviStructure confInitialSettings = (IIviStructure)iviSession.DataComponents["Configurable Initial Settings"];
                ConfigureInitialSettings(confInitialSettings);                
                ParseOptionString(OptionString);
                mdrCh = mdrObj.get_Chan(channelName);
                mdrCh.onStateChanged += new MDR32Lib._IMdrChanEvents_onStateChangedEventHandler(mdrCh_onStateChanged);
                mdrCh.onProgress += new _IMdrChanEvents_onProgressEventHandler(mdrCh_onProgress);
                mdrCh = mdrObj.get_Chan(channelName);

                currState = mdrCh.State;
                




                if (Reset)
                {
                    this.Reset();
                }
                _initialized = true;
            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_ALREADY_INITIALIZED));
            }

        }

        private void ConfigureInitialSettings(IIviStructure confInitialSettings)
        {
            foreach (IIviDataComponent dataComp in confInitialSettings.DataComponents)
            {
                //System.Diagnostics.Debug.WriteLine(dataComp.Name);
                string name = dataComp.Name;
                switch (name.ToLower())
                {
                    case "channelname":
                        channelName = ((IIviString)dataComp).Value;
                        break;

                    default:
                        iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_BAD_OPTION_NAME));
                        break;
                }


            }
        }



        #endregion

        #region IIviDriverUtility Members

        public void Disable()
        {
            if (_initialized)
            {
                mdrCh.Wind(0);
                //throw new NotImplementedException();
            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
            }
        }

        public override void ErrorQuery(ref int ErrorCode, ref string ErrorMessage)
        {

            ErrorMessage = mdrCh.ErrorInfo;
            if (ErrorMessage != "")
            {
                ErrorCode = -1;
            }
            else
            {
                ErrorCode = 0;
            }

        }

        public override void Reset()
        {
            if (_initialized)
            {
                mdrCh.Wind(0);
                interchangeWarningQueue.Enqueue("User called the Reset function");
                //throw new NotImplementedException();
            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));

            }
        }

        public override void ResetWithDefaults()
        {
            if (_initialized)
            {
                Reset();
                //throw new NotImplementedException();
            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
            }
        }

        #endregion

        #region IPositioningDevice Members

        PositioningDeviceState IPositioningDevice.State
        {
            get
            {
                if (_initialized)
                {
                    switch (mdrCh.State)
                    {
                        case (int)MDR32Lib.mdrState.mdrRunning:
                            return PositioningDeviceState.Running;

                        case (int)mdrState.mdrIdle:
                            return PositioningDeviceState.Idle;

                        case (int)mdrState.mdrError:
                            return PositioningDeviceState.Error;

                        default:
                            return PositioningDeviceState.Error;
                    }

                }
                else
                {
                    throw (new Exception("Driver is not initialized"));
                }

            }
        }

        public double Position
        {
            get
            {
                if (_initialized)
                {
                    return mdrCh.Val;
                }
                else
                {
                    throw (new Exception("Driver is not initialized"));
                }
            }
        }

        void IPositioningDevice.BeginMove(double pos)
        {
            if (_initialized)
            {
                mdrCh.Wind(pos);

            }
            else
            {
                throw (new Exception("Driver is not initialized"));
            }

        }

        void IPositioningDevice.Move(double pos)
        {
            throw new NotImplementedException();
        }

        private EventHandler<PositioningDevice.StateChangedEventArgs> stateChangedEvent;
        private EventHandler<PositioningDevice.FinishEventArgs> finishEvent;
        private EventHandler<PositioningDevice.ProgressEventArgs> progressEvent;


        event EventHandler<PositioningDevice.StateChangedEventArgs> IPositioningDevice.StateChangedEvent
        {
            add { stateChangedEvent += value; }
            remove { stateChangedEvent -= value; }
        }

        event EventHandler<PositioningDevice.FinishEventArgs> IPositioningDevice.FinishEvent
        {
            add { finishEvent += value; }
            remove { finishEvent -= value; }
        }

        event EventHandler<PositioningDevice.ProgressEventArgs> IPositioningDevice.ProgressEvent
        {
            add { progressEvent += value; }
            remove { progressEvent -= value; }
        }

        protected virtual void OnProgressEvent(PositioningDevice.ProgressEventArgs e)
        {
            EventHandler<PositioningDevice.ProgressEventArgs> handler = progressEvent;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        protected virtual void OnFinishEvent(PositioningDevice.FinishEventArgs e)
        {
            EventHandler<PositioningDevice.FinishEventArgs> handler = finishEvent;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        protected virtual void OnStateChangedEvent(PositioningDevice.StateChangedEventArgs e)
        {
            EventHandler<PositioningDevice.StateChangedEventArgs> handler = stateChangedEvent;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        #endregion
    }
}
